/*
Copyright 2024 - 2025 Zen HuiFer

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
	"context"
	"encoding/json"
	amqp "github.com/rabbitmq/amqp091-go"
	"go.mongodb.org/mongo-driver/bson"
	"go.uber.org/zap"
	"iot-notice/models"
	"strconv"
	"time"
)

// HandlerWaring 是一个处理预警消息的函数
//
// 参数：
// messages <-chan amqp.Delivery: 接收AMQP消息的通道
//
// 返回值：
// 无
func HandlerWaring(messages <-chan amqp.Delivery) {

	go func() {
		for d := range messages {

			HandlerWaringString(d)
			err := d.Ack(false)
			if err != nil {
				zap.S().Errorf("消息确认异常：%+v", err)

			}

		}
	}()

	zap.S().Infof(" [*] Waiting for messages. To exit press CTRL+C")
}

// HandlerWaringString 是一个处理来自AMQP的报警信息的函数
// 参数d是AMQP的交付对象
// 函数返回一个布尔值，表示处理是否成功
func HandlerWaringString(d amqp.Delivery) bool {
	var data []DataRowList
	err := json.Unmarshal(d.Body, &data)
	if err != nil {
		zap.S().Infof("Failed to unmarshal message: %s body = %s", err, string(d.Body))
		return false
	}
	for i := 0; i < len(data); i++ {
		// 解引用指针并访问切片中的元素
		row := (data)[i]

		handlerWaringOnce(row)

	}
	return true
}

// handlerWaringOnce 处理警告处理器数据的函数
//
// 参数：
//
//	- msg DataRowList 包含反序列化后的消息的数据行列表
//
// 返回值：
//
//	- bool  表示是否处理成功
func handlerWaringOnce(msg DataRowList) {
	// 打印反序列化后的消息
	zap.S().Debugf("处理 waring_handler 数据: %+v", msg)

	uid := msg.DeviceUid
	// 1. 根据设备UID（mqtt客户端ID）获取所有信号

	mapping := getMqttClientMappingSignalWarningConfig(uid, msg.IdentificationCode)
	db := GMongoClient.Database(globalConfig.MongoConfig.Db)

	for _, row := range msg.DataRows {
		configs := mapping[row.Name]

		floatValue, err := strconv.ParseFloat(row.Value, 64)
		if err != nil {
			zap.S().Errorf("字符串转换出错: %s", err)
			continue
		}
		for _, config := range configs {

			// fixme: 消息推送
			zap.S().Infof("配置ID: %d 信号名称: %s, 范围小值: %f, 范围大值: %f, 1=范围内报警 0=范围外报警: %d\n", config.ID, row.Name, config.Min, config.Max, config.InOrOut)

			if config.InOrOut == 1 {
				if config.Min <= floatValue && floatValue <= config.Max {
					// 在范围内，根据需求执行操作
					zap.S().Infof("当前信号 %s  值在范围内: %+v 命中规则ID %d", row.Name, floatValue, config.ID)
					m := bson.M{
						"device_uid":  uid,
						"signal_name": row.Name,
						"signal_id":   config.SignalId,
						"value":       floatValue,
						"rule_id":     config.ID,
						"insert_time": time.Now().Unix(),
						"up_time":     msg.Time,
					}
					name := CalcCollectionName(globalConfig.MongoConfig.WaringCollection, uint(config.ID))
					collection := db.Collection(name)
					one, err := collection.InsertOne(context.TODO(), m)
					if err != nil {
						zap.S().Errorf("插入数据失败: %+v", err)
					} else {
						zap.S().Infof("插入数据成功: %s", one.InsertedID)
					}
				}

			} else {
				if floatValue < config.Min || floatValue > config.Max {
					// 范围外报警
					zap.S().Infof("当前信号 %s 范围外报警: %+v 命中规则ID %d", row.Name, floatValue, config.ID)
					m := bson.M{
						"device_uid":  uid,
						"signal_name": row.Name,
						"signal_id":   config.SignalId,
						"value":       floatValue,
						"rule_id":     config.ID,
						"insert_time": time.Now().Unix(),
						"up_time":     msg.Time,
					}

					name := CalcCollectionName(globalConfig.MongoConfig.WaringCollection, uint(config.ID))
					collection := db.Collection(name)
					one, err := collection.InsertOne(context.TODO(), m)
					if err != nil {
						zap.S().Errorf("插入数据失败: %+v", err)
					} else {
						zap.S().Infof("插入数据成功: %s", one.InsertedID)
					}
				}
			}

			// fixme: 将报警元数据分发到不同的数据推送通道。
			mt := models.MessageTemplate{
				GeneratorTime: msg.Time,
				DeviceUid:     uid,
				SignalId:      config.SignalId,
				MqttClientId:  uid,
				SignalName:    row.Name,
				SignalValue:   floatValue,
				Min:           config.Min,
				Max:           config.Max,
				Unit:          config.Unit,
				InOrOut:       config.InOrOut,
			}

			jsonData, err := json.Marshal(mt)
			if err != nil {
				zap.S().Errorf("消息模板 %s", err)
				return
			}
			PushToQueue("waring_notice", jsonData)

		}

	}

}

// getMqttClientMappingSignalWarningConfig 根据 MQTT 客户端 ID 获取信号警告配置的映射
//
// 参数:
//
//	- mqtt_client_id string  MQTT 客户端 ID
//
// 返回值:
//
//	- map[string][]SignalWaringConfig - 信号名称到信号警告配置切片的映射
func getMqttClientMappingSignalWarningConfig(mqttClientId string, code string) map[string][]SignalWaringConfig {
	background := context.Background()
	result, err := globalRedisClient.LRange(background, "signal:"+mqttClientId+":"+code, 0, -1).Result()
	if err != nil {
		// 处理错误，例如记录日志或返回错误
		zap.S().Errorf("获取信号列表失败: %+v", err)
	}

	// 创建一个映射，用于存放 signal.Name 到 swcs 的映射
	mapping := make(map[string][]SignalWaringConfig)

	for _, strSignal := range result {
		var signal Signal
		err := json.Unmarshal([]byte(strSignal), &signal)
		if err != nil {
			continue // 如果反序列化失败，跳过当前信号
		}

		result2, err := globalRedisClient.LRange(background, "waring:"+strconv.Itoa(signal.ID), 0, -1).Result()
		if err != nil {
			continue // 如果获取 warning 列表失败，跳过当前信号
		}

		var swcs []SignalWaringConfig
		for _, sw := range result2 {
			var swc SignalWaringConfig
			err := json.Unmarshal([]byte(sw), &swc)
			if err != nil {
				continue // 如果反序列化失败，跳过当前警告配置
			}
			swc.Unit = signal.Unit
			swcs = append(swcs, swc)
		}

		// 将解析后的 swcs 切片与 signal.Name 关联，并存储到映射中
		mapping[signal.Name] = swcs
	}

	return mapping
}
